#include"../header/borwein.h"



void borweinSeq(FILE *arquivo)
{
	/*declaracao*/
	int i = 0;
	int bits = 33219281; /* 10^7 * log(10) */ 
	unsigned int calc; 
	struct timeval inicial, final;

	mpf_t a, y, pi;
	mpf_t a0, y0, pi0;
	mpf_t aux, delta, precision;

	/*inicializacao*/
	printf("inicializacao...\n");	
	mpf_set_default_prec(bits);
	
	mpf_init(a);
	mpf_init(y);	
	mpf_init(pi);
	
	mpf_init(a0);
	mpf_init(y0);	
	mpf_init(pi0);

	mpf_init(aux);
	mpf_init(delta);
	mpf_init(precision);
	
	inicial = tempo();

	/*setando variaveis para a primeira iteracao*/
	printf("setando variaveis...\n");
	mpf_set_ui(a0,6);
	mpf_sqrt_ui(aux,2);
	mpf_mul_ui(aux,aux,4);
	mpf_sub(a0,a0,aux);
	
	mpf_sqrt_ui(y0,2);
	mpf_sub_ui(y0,y0,1);
	
	mpf_set_ui(delta,1);
	
	/*setando a precisao*/
	mpf_set_d(precision,10);
	mpf_pow_ui(precision,precision,10000000);
	mpf_ui_div(precision,1,precision);
	
	mpf_ui_div(pi0,1,a0);

	printf("iniciando procedimento...\n");

	while( mpf_cmp(delta,precision) > 0 )
	{
		/*calculo do y*/
		mpf_pow_ui(aux,y0,4);
		mpf_ui_sub(aux,1,aux);
		mpf_sqrt(aux,aux);
		mpf_sqrt(aux,aux);
		
		mpf_ui_sub(y,1,aux);
		mpf_add_ui(aux,aux,1);
		mpf_div(y,y,aux);

		/*calculo do a*/
		mpf_add_ui(aux,y,1);
		mpf_pow_ui(aux,aux,4);
		mpf_mul(a,a0,aux);
		
		mpf_pow_ui(aux,y,2);
		mpf_add(aux,aux,y);
		mpf_add_ui(aux,aux,1);
		mpf_mul(aux,aux,y);
		
		calc = 2*i + 3;
		mpf_set_ui(a0,2);
		mpf_pow_ui(a0,a0,calc);
		mpf_mul(aux,a0,aux);
		
		mpf_sub(a,a,aux);

		/*calculo de pi*/
		mpf_ui_div(pi,1,a);
		
		/*calculo da diferenca*/
		mpf_sub(delta,pi,pi0); 
		mpf_abs(delta,delta);
	
		/*atribuicao dos valores novos nos antigos*/
		mpf_set(a0,a);
		mpf_set(y0,y);
		mpf_set(pi0,pi);
		

		printf("fim da iteracao %d\n",i);
		i++;
	}

	final = tempo();

	printf("Tempo de execucao: %.3lf s\n", difftempo(final,inicial));

	mpf_out_str (arquivo, 10, 10000001, pi);

	mpf_clear(a);
	mpf_clear(y);
	mpf_clear(a0);
	mpf_clear(y0);
	mpf_clear(pi);
	mpf_clear(pi0);
	mpf_clear(aux);
	mpf_clear(delta);
	mpf_clear(precision);

	printf("fim do processo...\n");
	
}


/*variaveis paralelas*/
mpf_t a_par, y_par, pi_par;
mpf_t a0_par, y0_par, pi0_par;
mpf_t delta_par, precision_par;
int convergiu;

void * calc_a_borwein(void * i)
{
	mpf_t aux_par;
	int calc;

	mpf_init(aux_par);
	
	mpf_add_ui(aux_par,y0_par,1);
	mpf_pow_ui(aux_par,aux_par,4);
	mpf_mul(a_par,a0_par,aux_par);
	
	mpf_pow_ui(aux_par,y0_par,2);
	mpf_add(aux_par,aux_par,y0_par);
	mpf_add_ui(aux_par,aux_par,1);
	mpf_mul(aux_par,aux_par,y0_par);
	
	calc = 2*((int)i) + 3;
	mpf_set_ui(a0_par,2);
	mpf_pow_ui(a0_par,a0_par,calc);
	mpf_mul(aux_par,a0_par,aux_par);
		
	mpf_sub(a_par,a_par,aux_par);

	return NULL;
}

void * calc_y()
{
	mpf_t aux_par;

	mpf_init(aux_par);

	mpf_pow_ui(aux_par,y0_par,4);
	mpf_ui_sub(aux_par,1,aux_par);
	mpf_sqrt(aux_par,aux_par);
	mpf_sqrt(aux_par,aux_par);
	
	mpf_ui_sub(y_par,1,aux_par);
	mpf_add_ui(aux_par,aux_par,1);
	mpf_div(y_par,y_par,aux_par);

	
	return NULL;
}

void * calc_pi()
{
	mpf_ui_div(pi_par,1,a0_par);
		
	mpf_sub(delta_par,pi_par,pi0_par); 
	mpf_abs(delta_par,delta_par);

	if(mpf_cmp(delta_par,precision_par) < 0)
		convergiu = 1;

	return NULL;
}

void borweinPar(FILE *arquivo)
{
	int i = 1; 	
	int bits = 33219281; /* 10^7 * log(10) */
	struct timeval inicial, final; 

	pthread_t a_thread, y_thread, pi_thread;
	convergiu = 0;
	mpf_t aux;

	/*inicializacao*/
	printf("inicializacao...\n");	
	mpf_set_default_prec(bits);
	
	mpf_init(a_par);
	mpf_init(y_par);	
	mpf_init(pi_par);
	
	mpf_init(a0_par);
	mpf_init(y0_par);	
	mpf_init(pi0_par);

	mpf_init(aux);
	mpf_init(delta_par);
	mpf_init(precision_par);
	
	inicial = tempo();
	
	/*setando variaveis para a primeira iteracao*/
	printf("setando variaveis...\n");
	mpf_set_ui(a0_par,6);
	mpf_sqrt_ui(aux,2);
	mpf_mul_ui(aux,aux,4);
	mpf_sub(a0_par,a0_par,aux);
	
	mpf_sqrt_ui(y0_par,2);
	mpf_sub_ui(y0_par,y0_par,1);
	
	mpf_set_ui(delta_par,1);
	
	/*setando a precisao*/
	mpf_set_d(precision_par,10);
	mpf_pow_ui(precision_par,precision_par,10000000);
	mpf_ui_div(precision_par,1,precision_par);
	
	mpf_ui_div(pi0_par,1,a0_par);


	printf("iniciando procedimento...\n");
    /* Primeira iteracao do pipeline */	
	calc_y();
    mpf_set(y0_par, y_par);
	printf("fim da iteracao 0\n");

	/* Segunda iteracao do pipeline */
	pthread_create(&y_thread,NULL,calc_y,NULL);
	pthread_create(&a_thread,NULL,calc_a_borwein,(void *) 0);
	pthread_join(y_thread,NULL);
	pthread_join(a_thread,NULL);

	mpf_set(a0_par,a_par);
	mpf_set(y0_par,y_par);

	printf("fim da iteracao 1\n");

	/* Demais iteracoes do pipeline */
	while(!convergiu)
	{
		pthread_create(&y_thread,NULL,calc_y,NULL);
		pthread_create(&a_thread,NULL,calc_a_borwein, (void *) i);
		pthread_create(&pi_thread,NULL,calc_pi,NULL);

		pthread_join(y_thread,NULL);
		pthread_join(a_thread,NULL);
		pthread_join(pi_thread,NULL);
	
		/*atribuicao dos valores novos nos antigos*/
		mpf_set(a0_par,a_par);
		mpf_set(y0_par,y_par);
		mpf_set(pi0_par,pi_par);
		
		i++;
		printf("fim da iteracao %d\n",i);
	}
	
	final = tempo();

    printf("Tempo de execucao: %.3lf s\n", difftempo(final,inicial));

	mpf_out_str (arquivo, 10, 10000001, pi_par);
	
	mpf_clear(a_par);
	mpf_clear(y_par);
	mpf_clear(a0_par);
	mpf_clear(y0_par);
	mpf_clear(pi_par);
	mpf_clear(pi0_par);
	mpf_clear(aux);
	mpf_clear(delta_par);
	mpf_clear(precision_par);

	printf("fim do processo...\n");

}

